/*
 * Copyright 2010 Michael Nitsche
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.mnit.basis.swt.spezial;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.TreeItem;

import de.mnit.basis.daten.struktur.S_Folge;
import de.mnit.basis.daten.struktur.container.Engpass;
import de.mnit.basis.daten.struktur.gruppe.Gruppe2;
import de.mnit.basis.daten.struktur.gruppe.Gruppe3;
import de.mnit.basis.daten.struktur.liste.Liste;
import de.mnit.basis.daten.struktur.liste.S_Liste;
import de.mnit.basis.daten.struktur.tabelle.S_Tabelle;
import de.mnit.basis.swt.anw.A_MN_Gruppe;
import de.mnit.basis.swt.dnd.transfer.IDObjekt;
import de.mnit.basis.swt.element.S_SWT_Komponente;
import de.mnit.basis.swt.element.feld.baum.SWT_BaumFeld;
import de.mnit.basis.swt.element.steuer.rollbar.gruppe.baum.Ordner;
import de.mnit.basis.swt.element.steuer.rollbar.gruppe.baum.SWT_Baum_N2M;
import de.mnit.basis.swt.statisch.FarbManager;
import de.mnit.basis.sys.Ausgabe;
import de.mnit.basis.sys.event.S_Extern;
import de.mnit.basis.sys.event.S_Zuhoerer;

/**
 * @author Michael Nitsche
 * 08.06.2010	Erstellt
 *
 * Features:
 * - Umbenennen
 * - Verschieben
 * - Hilfs-Funktionen
 *
 * TODO neu Strukturieren
 */
public class SWTX_Baum extends A_MN_Gruppe<SWTX_Baum> {

	private static final String E_AUSWAHL="auswahl";
	private static final String E_UMBENENNEN="umbenennen";

	private final SWT_Baum_N2M	k_baum = new SWT_Baum_N2M();
	private S_Extern<Integer,Gruppe2<Integer,String>> externPlus=null;
	private S_Extern<Integer,Boolean> externMinus=null;
	private S_Extern<Integer,String> externStdBild=null;
	private S_Extern<Integer,Boolean> externEditOk=null;


	public void plus() {
		S_Liste<SWT_BaumFeld> auswahl=t.k_baum.gAusgewaehlt();
		plus(auswahl.gLaenge()!=1 ? null : auswahl.gib(1));
	}

	public void minusAuswahl() {
		S_Liste<SWT_BaumFeld> auswahl=t.k_baum.gAusgewaehlt();
		if(auswahl.gLaenge()!=1)
			return;
		minus(auswahl.gib(1));
	}

	public SWT_Baum_N2M gBaum() {
		return this.k_baum;
	}

	public void eUmbenennen(S_Zuhoerer<Gruppe2<Integer,String>> z) {
		t.zuhoererPlus(E_UMBENENNEN, z);
	}

	public void sHintergrund(int id, Color c) {
		this.k_baum.sHintergrund(id, c);
	}

	public void sExternPlus(S_Extern<Integer,Gruppe2<Integer,String>> e) {
		this.externPlus=e;
	}

	public void sExternMinus(S_Extern<Integer,Boolean> e) {
		this.externMinus=e;
	}

	public void sExternStdBild(S_Extern<Integer,String> e) {
		this.externStdBild=e;
	}

	public void sExternEditOk(S_Extern<Integer,Boolean> e) {
		this.externEditOk=e;
	}

	public void sExternVerschieben(S_Extern<Gruppe3<Integer, Integer, Integer>, Boolean> e) {
		this.k_baum.sExternVerschieben(e);
	}

	public void sExternDrop(S_Extern<Gruppe2<SWT_BaumFeld,IDObjekt[]>,Boolean> e) {
		this.k_baum.sExternDrop(e);
	}

//	public void sOffen(TypTabelle2<Integer,Boolean> tab) {
//		this.k_baum.sOffen(tab);
//	}

	public Integer gAuswahlID() {
		S_Liste<SWT_BaumFeld> felder=t.k_baum.gAusgewaehlt();
		return felder!=null && felder.gLaenge()==1 ? t.k_baum.gID(felder.gib(1)) : null;
	}

	public void eVaterUngueltig(S_Zuhoerer<S_Folge<Ordner>> z) {
		this.k_baum.eVaterUngueltig(z);
	}

	//Spalten: ID, VATER_ID, TITEL, BILD, OFFEN
	public void setze(S_Tabelle<String> tab) {
		S_Liste<Ordner> l=Liste.neu();
		for(S_Folge<String> z : tab)
			l.plus(new Ordner(
				Integer.parseInt(z.gib(1)),
				z.gib(2)==null ? null : Integer.parseInt(z.gib(2)),
				z.gib(3),
				z.gib(4),
				Boolean.parseBoolean(z.gib(5))
			));
		this.k_baum.setze(l);
	}

	public void sAuswahl(int id) {
		t.k_baum.sAuswahl(id);
	}

	public void eAuswahl(S_Zuhoerer<SWT_BaumFeld[]> z) {
		t.zuhoererPlus(E_AUSWAHL, z);
	}

	public SWT_BaumFeld gFeld(Point p) {
		int x=p.x;
		int y=p.y;
		return t.k_baum.gItemXY(x, y);
	}

	public SWT_BaumFeld gFeld(int id) {
		return t.k_baum.gFeld(id);
	}

	public Integer gID(Point p) {
		SWT_BaumFeld feld=gFeld(p);
		return feld==null ? null : this.k_baum.gID(feld);
	}

	public void plus(SWT_BaumFeld feld) {
		if(this.externPlus==null)
			return;
		Integer root_id= feld==null ? null : t.k_baum.gID(feld);
		if(root_id!=null && root_id<0) //Negative ID
			root_id=null;
//		Ausgabe.debug(root_id);
		Gruppe2<Integer,String> id_titel=this.externPlus.verarbeite(root_id);
//		Ausgabe.debug(id_titel);
		if(id_titel==null || id_titel.g1()==null)
			return;
		String bild=this.externStdBild==null ? null : this.externStdBild.verarbeite(id_titel.g1());
		this.k_baum.plus(new Ordner(id_titel.g1(), root_id, id_titel.g2(), bild, false));
	}

	public void minus(SWT_BaumFeld feld) {
		if(this.externMinus==null)
			return;
		if(feld==null || feld.gKinderAnzahl()>0)
			return;
		Integer id= t.k_baum.gID(feld);
		if(id==null || id<0) //Negative ID
			return;
		boolean ok=this.externMinus.verarbeite(id);
		if(!ok)
			return;
		this.k_baum.minus(id);
	}

	// Editor //TODO Übernommen aus Snippet111 > Prüfen
	private TreeEditor editor = null; //Nicht sehr schön!
	public void umbenennen(SWT_BaumFeld feld) {
		if(editor==null)
			editor=new TreeEditor(t.k_baum.swt());
		final TreeItem item=feld.swt();
		boolean isCarbon = SWT.getPlatform().equals("carbon");
		Ausgabe.debug(SWT.getPlatform());
		final Composite composite = new Composite(t.k_baum.swt(), SWT.NONE);
		if(!isCarbon) composite.setBackground(FarbManager.gFarbe(0,0,0));
		final Text text = new Text(composite, SWT.NONE);
		final int offset = isCarbon ? 0 : 1;
		composite.addListener(SWT.Resize, new Listener() {
			public void handleEvent(Event e) {
				Rectangle rect = composite.getClientArea();
				text.setBounds(rect.x+offset, rect.y+offset, rect.width-offset*2, rect.height-offset*2);
			}
		});
		text.addListener(SWT.FocusOut, new Listener() {
			public void handleEvent(Event e) {
				String neu=text.getText();
				item.setText(neu);
				Ausgabe.debug("FocusOut", neu);
				Integer id=t.k_baum.gID(item);
				t.zuhoererStart(E_UMBENENNEN, Gruppe2.neu(id, neu));
				composite.dispose();
			}
		});
		text.addListener(SWT.Traverse, new Listener() {
			public void handleEvent(Event e) {
				switch(e.detail) {
					case SWT.TRAVERSE_RETURN:
						String neu=text.getText();
						item.setText(neu);
						Integer id=t.k_baum.gID(item);
						t.zuhoererStart(E_UMBENENNEN, Gruppe2.neu(id, neu));
						//Absichtlich ohne Break
					case SWT.TRAVERSE_ESCAPE:
						Ausgabe.debug("Ende", text.getText());
						composite.dispose();
						e.doit = false;
				}
			}
		});
		text.addListener(SWT.Verify, new Listener() {
			public void handleEvent(Event e) {
				String neu = text.getText();
				String links = neu.substring(0, e.start);
				String rechts = neu.substring(e.end, neu.length());
//				Ausgabe.debug(neu, links, rechts);
				GC gc = new GC(text);
				Point size = gc.textExtent(links + e.text + rechts);
				gc.dispose();
				size = text.computeSize(size.x, SWT.DEFAULT);
				editor.horizontalAlignment = SWT.LEFT;
				Rectangle itemRect = item.getBounds(), rect = t.k_baum.swt().getClientArea();
				editor.minimumWidth = Math.max(size.x, itemRect.width) + offset * 2;
				int left = itemRect.x, right = rect.x + rect.width;
				editor.minimumWidth = Math.min(editor.minimumWidth, right - left);
				editor.minimumHeight = size.y + offset * 2;
				editor.layout();
			}
		});
		editor.setEditor(composite, item);
		text.setText(item.getText());
		text.selectAll();
		text.setFocus();
	}

	// ERZEUGEN

	protected S_SWT_Komponente<?, ? extends Composite> layout() {
		return t.k_baum;
	}

	protected void initStyle() {
		t.k_baum.sDragNDrop();
	}

	protected void initEvents() {
		t.k_baum.eTaste(new KeyListener() {
			public void keyPressed(KeyEvent e) {}
			public void keyReleased(KeyEvent e) {
				Point cursor=t.gDisplay().getCursorLocation();
//				Ausgabe.text(e.keyCode, cursor);
				if(e.keyCode==SWT.DEL)
					minus(gFeld((cursor)));
			}
		});

		t.k_baum.eAuswahl(new Listener() {
			public void handleEvent(Event e) {
				TreeItem[] ta=t.k_baum.swt().getSelection();
				SWT_BaumFeld[] erg=new SWT_BaumFeld[ta.length];
				for(int i=0; i<ta.length; i++)
					erg[i]=(SWT_BaumFeld)ta[i].getData();
				t.zuhoererStart(E_AUSWAHL, erg);
			}
		});

		final Engpass<TreeItem> letztes = Engpass.neu();
		t.k_baum.swt().addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				final TreeItem item = (TreeItem)event.item;
				if(item != null && item == letztes.g() && externEditOk.verarbeite(t.k_baum.gID(item)))
					umbenennen((SWT_BaumFeld)item.getData());
				letztes.s(item);
			}
		});
	}

}
